<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Spring源码分析 | 辉辉的学习基地</title>
    <meta name="generator" content="VuePress 1.7.1">
    <link rel="icon" href="/blog/favicon.ico">
    <meta name="description" content="辉辉的学习基地是辉辉的个人博客，用于记录学习笔记、分享音乐、书籍、旅行等个人兴趣的站点。">
    <meta name="keywords" content="辉辉,辉辉的博客,博客,个人博客,vue,vuejs,vuepress,vuepress-theme-reco">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
    
    <link rel="preload" href="/blog/assets/css/0.styles.bbb0eee4.css" as="style"><link rel="preload" href="/blog/assets/js/app.4c41a59b.js" as="script"><link rel="preload" href="/blog/assets/js/2.a039f8e7.js" as="script"><link rel="preload" href="/blog/assets/js/29.b316a480.js" as="script"><link rel="preload" href="/blog/assets/js/4.bae9b8d2.js" as="script"><link rel="prefetch" href="/blog/assets/js/10.969d578d.js"><link rel="prefetch" href="/blog/assets/js/11.f93921d3.js"><link rel="prefetch" href="/blog/assets/js/12.a794f274.js"><link rel="prefetch" href="/blog/assets/js/13.d33e075d.js"><link rel="prefetch" href="/blog/assets/js/14.4da4367b.js"><link rel="prefetch" href="/blog/assets/js/15.bd9bf192.js"><link rel="prefetch" href="/blog/assets/js/16.318edc0e.js"><link rel="prefetch" href="/blog/assets/js/17.ebff9194.js"><link rel="prefetch" href="/blog/assets/js/18.17c4bd0a.js"><link rel="prefetch" href="/blog/assets/js/19.3a3638ec.js"><link rel="prefetch" href="/blog/assets/js/20.a1758358.js"><link rel="prefetch" href="/blog/assets/js/21.e2937215.js"><link rel="prefetch" href="/blog/assets/js/22.044317b3.js"><link rel="prefetch" href="/blog/assets/js/23.da1cba87.js"><link rel="prefetch" href="/blog/assets/js/24.8906d05f.js"><link rel="prefetch" href="/blog/assets/js/25.8c51032b.js"><link rel="prefetch" href="/blog/assets/js/26.37e22ab7.js"><link rel="prefetch" href="/blog/assets/js/27.a9db888c.js"><link rel="prefetch" href="/blog/assets/js/28.d5f797ba.js"><link rel="prefetch" href="/blog/assets/js/3.a38811c1.js"><link rel="prefetch" href="/blog/assets/js/30.6daf7445.js"><link rel="prefetch" href="/blog/assets/js/31.a2aab18e.js"><link rel="prefetch" href="/blog/assets/js/32.e1bb66d4.js"><link rel="prefetch" href="/blog/assets/js/33.53b2c8e5.js"><link rel="prefetch" href="/blog/assets/js/34.20d63ca4.js"><link rel="prefetch" href="/blog/assets/js/35.f06bac5f.js"><link rel="prefetch" href="/blog/assets/js/36.620f1a31.js"><link rel="prefetch" href="/blog/assets/js/37.88e5acfc.js"><link rel="prefetch" href="/blog/assets/js/38.f8c44d81.js"><link rel="prefetch" href="/blog/assets/js/39.bff4d281.js"><link rel="prefetch" href="/blog/assets/js/40.3d371cdd.js"><link rel="prefetch" href="/blog/assets/js/41.4b538139.js"><link rel="prefetch" href="/blog/assets/js/5.80fcdcaf.js"><link rel="prefetch" href="/blog/assets/js/6.e7d0e536.js"><link rel="prefetch" href="/blog/assets/js/7.de89b9df.js"><link rel="prefetch" href="/blog/assets/js/8.4d1ad321.js"><link rel="prefetch" href="/blog/assets/js/9.e842551c.js">
    <link rel="stylesheet" href="/blog/assets/css/0.styles.bbb0eee4.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container have-rightmenu" data-v-f848d4e8><div class="global-loading-wrapper" data-v-137da995 data-v-f848d4e8 data-v-f848d4e8><div class="loader-main" data-v-137da995><img src="/blog/assets/img/loading.18d75e19.gif" alt="loading" data-v-137da995></div></div> <div class="hide" data-v-f848d4e8><header class="navbar" data-v-f848d4e8><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/blog/" class="home-link router-link-active"><span class="site-name">辉辉的学习基地</span></a> <div class="links"><div class="color-picker"><a class="color-button"><i class="iconfont reco-color"></i></a> <div class="color-picker-menu" style="display:none;"><div class="mode-options"><h4 class="title">选择模式</h4> <ul class="color-mode-options"><li class="dark">深色模式</li><li class="light active">浅色模式</li><li class="read">阅读模式</li></ul></div></div></div> <div class="search-box"><i class="iconfont reco-search"></i> <input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <ul class="suggestions" style="display:none;"></ul></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/blog/" class="nav-link"><i class="iconfont reco-home"></i>首页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i></i>后端
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>文档教程</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/docs/nav/" class="nav-link"><i class="iconfont reco-blog"></i>资源导航
</a></li><li class="dropdown-subitem"><a href="/blog/docs/spring/" class="nav-link"><i class="iconfont reco-blog"></i>Spring官网
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-api"></i>索引
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/categories/" class="nav-link"><i class="iconfont reco-category"></i>分类
</a></li><li class="dropdown-item"><!----> <a href="/blog/tags/" class="nav-link"><i class="iconfont reco-tag"></i>标签
</a></li><li class="dropdown-item"><!----> <a href="/blog/archives/" class="nav-link"><i class="iconfont reco-date"></i>归档
</a></li></ul></div></div><div class="nav-item"><a href="/blog/bookshop/message-board/" class="nav-link"><i class="iconfont reco-suggestion"></i>留言板
</a></div><div class="nav-item"><a href="/blog/docs/nav/" class="nav-link"><i class="iconfont reco-api"></i>资源导航
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-message"></i>关于
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>联系</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://github.com/YanHui-Yang" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-github"></i>GitHub
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="/blog/bookshop/linkme/" class="nav-link"><i class="iconfont reco-account"></i>关于我
</a></li></ul></li><li class="dropdown-item"><h4>博客</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://github.com/YanHui-Yang/blog" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-document"></i>本站源码
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></li><li class="dropdown-item"><h4>其他</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/bookshop/friendslink/" class="nav-link"><i class="iconfont reco-friend"></i>友情链接
</a></li></ul></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask" data-v-f848d4e8></div> <aside class="sidebar" data-v-f848d4e8><div class="personal-info-wrapper" data-v-2cb066a4 data-v-f848d4e8><img src="/blog/img/logo.png" alt="author-avatar" class="personal-img" data-v-2cb066a4> <div class="author" data-v-2cb066a4>
    辉辉
  </div> <div class="personal-info-details" data-v-2cb066a4><div data-v-2cb066a4>文章：<span data-v-2cb066a4>19</span></div> <div data-v-2cb066a4>地点：<span data-v-2cb066a4>广东·广州</span></div></div> <div class="slogan" data-v-2cb066a4>
    Just do it
  </div> <ul class="social-links" data-v-2cb066a4><li class="social-item" data-v-2cb066a4><i class="iconfont reco-github" style="color:#24292e;" data-v-2cb066a4></i></li><li class="social-item" data-v-2cb066a4><i class="iconfont reco-csdn" style="color:#ff4d4d;" data-v-2cb066a4></i></li></ul></div> <nav class="nav-links"><div class="nav-item"><a href="/blog/" class="nav-link"><i class="iconfont reco-home"></i>首页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i></i>后端
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>文档教程</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/docs/nav/" class="nav-link"><i class="iconfont reco-blog"></i>资源导航
</a></li><li class="dropdown-subitem"><a href="/blog/docs/spring/" class="nav-link"><i class="iconfont reco-blog"></i>Spring官网
</a></li></ul></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-api"></i>索引
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/blog/categories/" class="nav-link"><i class="iconfont reco-category"></i>分类
</a></li><li class="dropdown-item"><!----> <a href="/blog/tags/" class="nav-link"><i class="iconfont reco-tag"></i>标签
</a></li><li class="dropdown-item"><!----> <a href="/blog/archives/" class="nav-link"><i class="iconfont reco-date"></i>归档
</a></li></ul></div></div><div class="nav-item"><a href="/blog/bookshop/message-board/" class="nav-link"><i class="iconfont reco-suggestion"></i>留言板
</a></div><div class="nav-item"><a href="/blog/docs/nav/" class="nav-link"><i class="iconfont reco-api"></i>资源导航
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-message"></i>关于
    </span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>联系</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://github.com/YanHui-Yang" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-github"></i>GitHub
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-subitem"><a href="/blog/bookshop/linkme/" class="nav-link"><i class="iconfont reco-account"></i>关于我
</a></li></ul></li><li class="dropdown-item"><h4>博客</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="https://github.com/YanHui-Yang/blog" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-document"></i>本站源码
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></li><li class="dropdown-item"><h4>其他</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/blog/bookshop/friendslink/" class="nav-link"><i class="iconfont reco-friend"></i>友情链接
</a></li></ul></li></ul></div></div> <!----></nav> <ul class="sidebar-links"><li><a href="/blog/pages/47051574c0b3b/" class="sidebar-link">Spring基础</a></li><li><a href="/blog/pages/b937bc3a16f66/" aria-current="page" class="active sidebar-link">Spring源码分析</a></li><li><a href="/blog/pages/eb9794eecd247/" class="sidebar-link">Spring Cloud基础</a></li><li><a href="/blog/pages/ad577fcaceee3/" class="sidebar-link">Spring Data基础</a></li></ul> </aside> <div><main class="page"><div class="theme-vdoing-wrapper bg-style-3"><div class="articleInfo-wrap" data-v-13f19dad><div class="articleInfo" data-v-13f19dad><ul class="breadcrumbs" data-v-13f19dad><li data-v-13f19dad><a href="/blog/" title="首页" class="fa fa-laptop-house router-link-active" data-v-13f19dad></a></li> <li data-v-13f19dad><a href="/blog/categories/?category=Spring" title="分类" data-v-13f19dad>Spring</a></li> <!----> <!----></ul> <div class="info" data-v-13f19dad><div title="作者" class="author fa fa-user" data-v-13f19dad><a href="javascript:;" data-v-13f19dad>辉辉</a></div> <div title="创建时间" class="date fa fa-calendar-alt" data-v-13f19dad><a href="javascript:;" data-v-13f19dad>2021/08/23 15:05:22</a></div> <!----></div></div></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-content"></div></div></div> <h1><img src="">
            Spring源码分析
          </h1> <div class="theme-vdoing-content content__default"><h2 id="_1-引言"><a href="#_1-引言" class="header-anchor">#</a> 1. 引言</h2> <h3 id="_1-1-spring-与-spring-boot-的区别"><a href="#_1-1-spring-与-spring-boot-的区别" class="header-anchor">#</a> 1.1 Spring 与 Spring Boot 的区别</h3> <p>说 Spring 与 Spring Boot 的区别，其实旨意在说 Spring + Spring MVC 与 Spring Boot 的区别</p> <ol><li>简化 Spring + Spring MVC，在导入 Spring Boot Maven 依赖的时候可以看出（提供了很多 start）</li> <li>简化冗余配置（各种封装的 AutoConcfiguration）</li> <li>内嵌 tomcat
<ol><li>在 Spring MVC 中，是有父子工厂这个概念的（父工厂 ContextLoaderListener，子工厂 DispatcherServlet），Spring MVC 中的父子工厂需要解决事务的问题（Spring MVC 的事务是在父工厂中配置的，而 Controller 是子工厂 DispatcherServlet 创建的，DispatcherServlet 获取不到 父工厂配置的事务，解决方式：子工厂不要创建 Service，调用父工厂创建 Service）而Spring Boot 是没有父子容器的概念，因为它的 Tomcat 是内嵌的，不需要使用外部创建的方式去整合</li> <li>可以启动多个 Tomcat 进程</li></ol></li></ol> <h3 id="_1-2-spring-源码环境搭建"><a href="#_1-2-spring-源码环境搭建" class="header-anchor">#</a> 1.2 Spring 源码环境搭建</h3> <p>本次使用的 Spring 版本是 Spring 5.1.X</p> <div class="language-shell line-numbers-mode"><pre class="language-shell"><code><span class="token comment"># 克隆 Spring 源码</span>
<span class="token function">git</span> clone https://github.com/spring-projects/spring-framework.git
<span class="token comment"># 将源码导入 idea，会自动下载 gradle</span>
<span class="token comment"># 在根目录下的 build.gradle 文件修改 gradle镜像源为阿里云镜像，将下面配置放到 mavenCenter() 之上</span>
repositories <span class="token punctuation">{</span>
	maven <span class="token punctuation">{</span> url <span class="token string">'https://maven.aliyun.com/repository/public/'</span> <span class="token punctuation">}</span>
	maven <span class="token punctuation">{</span> url <span class="token string">'https://maven.aliyun.com/repository/spring/'</span> <span class="token punctuation">}</span>
	mavenCentral<span class="token punctuation">(</span><span class="token punctuation">)</span>
	maven <span class="token punctuation">{</span> url <span class="token string">&quot;https://repo.spring.io/libs-release&quot;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment"># 最后等待 build successful 即可</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><h2 id="_2-spring-ioc"><a href="#_2-spring-ioc" class="header-anchor">#</a> 2. Spring IOC</h2> <h3 id="_2-1-beanfactory"><a href="#_2-1-beanfactory" class="header-anchor">#</a> 2.1 BeanFactory</h3> <p>BeanFactory 是 Spring 体系中的底层工厂，定义了工厂最底层的工作</p> <p><strong>BeanFactory 的结构图</strong></p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/2.png" alt="2"></p> <ol><li><p>ApplicationContext 继承了 ListableBeanFactory，Listable 的意思就是，通过这个接口我们可以获取到多个 Bean，最顶层 BeanFactory 接口的方法都是获取单个 Bean 的</p></li> <li><p>ApplicationContext 继承了 HierarchicalBeanFactory，Hierarchical 单词本身已经能说明问题了，也就是说我们可以在应用中起多个 BeanFactory，然后可以将各个 BeanFactory 设置为父子关系</p></li> <li><p>AutowireCapableBeanFactory 这个名字中的 Autowire 大家都非常熟悉，它就是用来自动装配 Bean 用的，但是仔细看上图，ApplicationContext 并没有继承它，不过不用担心，不使用继承，不代表不可以使用组合，如果你看到 ApplicationContext 接口定义中的最后一个方法 getAutowireCapableBeanFactory() 就知道了</p></li> <li><p>ConfigurableListableBeanFactory 也是一个特殊的接口，看图，特殊之处在于它继承了第二层所有的三个接口，而 ApplicationContext 没有。这点之后会用到</p></li> <li><p>HierarchicalBeanFactory</p></li></ol> <blockquote><p>让父子容器具有继承的能力（父子容器的管理），它有 ConfigurableBeanFactory 和 ApplcationContext 这两个子类</p></blockquote> <ol start="2"><li>AutowireCapableBeanFactory</li></ol> <blockquote><p>具备自动注入的能力，让工厂具备初始化和销毁的能力（init，destory）</p></blockquote> <ol start="3"><li>ListableBeanFactory</li></ol> <blockquote><p>获取相关的配置信息（containsbeanDefinition、getBeanNameForType）ApplicationContext 也实现了这个接口，ApplicationContext 获取 Bean 信息就是通过这个接口实现的</p></blockquote> <ol start="4"><li>ConfigurableBeanFactory</li></ol> <blockquote><p>可配置工厂；对象的单实例、多实例就是该接口决定的，同时还包含类型转换器、后置处理Bean</p></blockquote> <ol start="5"><li>ApplicationContext</li></ol> <blockquote><p>工厂功能集大成者</p></blockquote> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210909211816304.png" alt="image-20210909211816304"></p> <ol start="6"><li>DefaultListableBeanFactory</li></ol> <blockquote><p>Spring 工厂中最为核心的工厂，具备自动注入、工厂初始化和销毁、单实例多实例对象的创建、类型转换器以及后置处理 Bean 的功能</p></blockquote> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210909211747876.png" alt="image-20210909211747876"></p> <ol start="7"><li>XmlBeanFactory</li></ol> <blockquote><p>继承自 DefaultListableBeanFactory，同时具备 Xml 的读取能力（具备 XmlBeanDefinitionReader）</p></blockquote> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210909211656398.png" alt="image-20210909211656398"></p> <p><strong>BeanFactory的源码</strong></p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">BeanFactory</span> <span class="token punctuation">{</span>

	<span class="token comment">// 这里是对FactoryBean的转义定义</span>
    <span class="token comment">// 如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象，转义符“&amp;”用来获取FactoryBean本身</span>
	<span class="token class-name">String</span> FACTORY_BEAN_PREFIX <span class="token operator">=</span> <span class="token string">&quot;&amp;&quot;</span><span class="token punctuation">;</span>

	<span class="token comment">// 根据bean的名字来获得IOC容器中的bean实例，需要强转</span>
	<span class="token class-name">Object</span> <span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span><span class="token punctuation">;</span>

	<span class="token comment">// 根据bean的名字和Class&lt;T&gt;来获得IOC容器中的bean实例</span>
    <span class="token comment">// 不需要强转，在函数内部根据Class&lt;T&gt;转换成目标类型</span>
	<span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">T</span> <span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">,</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> requiredType<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span><span class="token punctuation">;</span>

	<span class="token comment">// 根据bean的名称和指定显式构造函数 参数 获取目标bean</span>
	<span class="token class-name">Object</span> <span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span><span class="token punctuation">;</span>

	<span class="token comment">// 根据Class&lt;T&gt;来获得IOC容器中的bean实例 需要保证配置的目标类型唯一</span>
    <span class="token comment">// 不需要强转，在函数内部根据Class&lt;T&gt;转换成目标类型</span>
	<span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">T</span> <span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> requiredType<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span><span class="token punctuation">;</span>

	<span class="token comment">// 根据bean的名称和指定显式构造函数 参数类型 获取目标bean</span>
	<span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">T</span> <span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> requiredType<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span><span class="token punctuation">;</span>

	<span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">ObjectProvider</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token function">getBeanProvider</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> requiredType<span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">ObjectProvider</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token function">getBeanProvider</span><span class="token punctuation">(</span><span class="token class-name">ResolvableType</span> requiredType<span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token comment">// 根据bean的名称，判断是否已经包含该bean</span>
	<span class="token keyword">boolean</span> <span class="token function">containsBean</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token comment">// 根据bean的名称，判断该bean的实例是否为单例</span>
	<span class="token keyword">boolean</span> <span class="token function">isSingleton</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">NoSuchBeanDefinitionException</span><span class="token punctuation">;</span>

	<span class="token comment">// 根据bean的名称，判断该bean的实例是否为多例</span>
	<span class="token keyword">boolean</span> <span class="token function">isPrototype</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">NoSuchBeanDefinitionException</span><span class="token punctuation">;</span>

	<span class="token comment">// 检查给定名称的bean是否与指定的类型匹配</span>
	<span class="token keyword">boolean</span> <span class="token function">isTypeMatch</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">,</span> <span class="token class-name">ResolvableType</span> typeToMatch<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">NoSuchBeanDefinitionException</span><span class="token punctuation">;</span>

	<span class="token keyword">boolean</span> <span class="token function">isTypeMatch</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">,</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> typeToMatch<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">NoSuchBeanDefinitionException</span><span class="token punctuation">;</span>

	<span class="token comment">// 获取给定名称的bean的class</span>
	<span class="token annotation punctuation">@Nullable</span>
	<span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> <span class="token function">getType</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">NoSuchBeanDefinitionException</span><span class="token punctuation">;</span>

	<span class="token comment">// 返回给定bean名称的别名，如果有的话</span>
	<span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">getAliases</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br></div></div><p><strong>Spring IOC 源码学习所涵盖的内容</strong></p> <ol><li>怎么读取配置文件，获得 IO 资源</li> <li>读取配置文件后，如何在 Spring 中以对象的形式进行封装</li> <li>根据配置信息创建对象</li> <li>所创建对象的生命周期</li></ol> <p><strong>BeanDefinition 的常用子类 GenericBeanDefinition 类结构图</strong></p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210909211118260.png" alt="image-20210909211118260"></p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">BeanFactory</span> beanFactory <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XmlBeanFactory</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ClassPathResource</span><span class="token punctuation">(</span><span class="token string">&quot;spring/applicationContext.xml&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">User</span> user1 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">User</span><span class="token punctuation">)</span> beanFactory<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token string">&quot;user1&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>user1<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>最终可知，使用 XmlBeanFactory 可以实现 Spring Bean 的创建，但是 XmlBeanFactory 已经被废弃了，所以需要找替换品</p> <p><strong>使用 DefaultListableBeanFactory + XmlBeanDefinitionReader 替换 XmlBeanFactory</strong></p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">DefaultListableBeanFactory</span> beanFactory2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DefaultListableBeanFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Resource</span> resource <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ClassPathResource</span><span class="token punctuation">(</span><span class="token string">&quot;spring/applicationContext.xml&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">XmlBeanDefinitionReader</span> reader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XmlBeanDefinitionReader</span><span class="token punctuation">(</span>beanFactory2<span class="token punctuation">)</span><span class="token punctuation">;</span>
reader<span class="token punctuation">.</span><span class="token function">loadBeanDefinitions</span><span class="token punctuation">(</span>resource<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">User</span> user2 <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">User</span><span class="token punctuation">)</span> beanFactory2<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token string">&quot;user2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>user2<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><h3 id="_2-2-spring-如何解析默认标签"><a href="#_2-2-spring-如何解析默认标签" class="header-anchor">#</a> 2.2 Spring 如何解析默认标签？</h3> <p>XmlBeanFactory 有两个重载构造函数，一个是传 Resource，一个是传 Resource 和 parentBeanFactory，不得而知单参的构造是直接解析 Resource 配置文件资源，而它直接调用了双参的重载，传的 parentBeanFactory 为 null，也就是说它没有父工厂，而双参的构造函数就是让 BeanFactory 去设置父工厂的</p> <blockquote><p>Spring 允许开发者设置多个父工厂。而设置父工厂在开发中是非常不常见的，Spring MVC 中的父子工厂就是其中的一个使用 XmlBeanFactory 设置父工厂的案例</p></blockquote> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">XmlBeanFactory</span> <span class="token keyword">extends</span> <span class="token class-name">DefaultListableBeanFactory</span> <span class="token punctuation">{</span>

    <span class="token comment">// 解析配置文件，将配置文件的内容解析成BeanDefinition</span>
	<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">XmlBeanDefinitionReader</span> reader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XmlBeanDefinitionReader</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 单参的构造，然后该构造调用了双参的构造</span>
    <span class="token comment">// 其中单参传的parentBeanFactory为null，说明使用单参的XmlBeanFactory创建的Bean没有父工厂</span>
	<span class="token keyword">public</span> <span class="token class-name">XmlBeanFactory</span><span class="token punctuation">(</span><span class="token class-name">Resource</span> resource<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span>
		<span class="token keyword">this</span><span class="token punctuation">(</span>resource<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>

    <span class="token comment">// 双参的构造</span>
    <span class="token comment">// Spring允许Bean包含父工厂，调用双参去设置</span>
    <span class="token comment">// 在开发中开发Spring父子工厂的场景几乎没有，唯一遇到的就是在Spring MVC中的父子容器</span>
    <span class="token comment">// 父工厂ContextLoaderListener 子工厂DispatcherServlet</span>
	<span class="token keyword">public</span> <span class="token class-name">XmlBeanFactory</span><span class="token punctuation">(</span><span class="token class-name">Resource</span> resource<span class="token punctuation">,</span> <span class="token class-name">BeanFactory</span> parentBeanFactory<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span>
        <span class="token comment">// 交给父类去创建父工厂</span>
		<span class="token keyword">super</span><span class="token punctuation">(</span>parentBeanFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 使用XmlBeanDefinitionReader对象加载BeanDefinitions对象</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>reader<span class="token punctuation">.</span><span class="token function">loadBeanDefinitions</span><span class="token punctuation">(</span>resource<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br></div></div><p>在 XmlBeanFactory 中的代码可以看到，它使用了 reader 去加载配置文件并封装成 BeanDefinition 类，而 reader 就是用来解析 XML 的 XmlBeanDefinitionReader 类</p> <p>进入 this.reader.loadBeanDefinitions(resource) 看一下，Spring 重载了 loadBeanDefinitions() 方法</p> <p>查看 loadBeanDefinitions() 方法的重载，在改重载方法内，Spring 将读取到的输入流交给 InputSource 处理，同时设置编码，最后将 inputSource 对象和编码交给 doLoadBeanDefinitions 方法处理</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">loadBeanDefinitions</span><span class="token punctuation">(</span><span class="token class-name">Resource</span> resource<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeanDefinitionStoreException</span> <span class="token punctuation">{</span>
    <span class="token comment">// loadBeanDefinition的重载</span>
    <span class="token comment">// 这里的是先对resource进行了编码，但是因为我们配置文件中没有进行编码操作，所以编码为null</span>
    <span class="token keyword">return</span> <span class="token function">loadBeanDefinitions</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">EncodedResource</span><span class="token punctuation">(</span>resource<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">loadBeanDefinitions</span><span class="token punctuation">(</span><span class="token class-name">EncodedResource</span> encodedResource<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeanDefinitionStoreException</span> <span class="token punctuation">{</span>
    <span class="token comment">// ...编码校验和日志信息</span>
    
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token comment">// 获取resource的输入流</span>
        <span class="token class-name">InputStream</span> inputStream <span class="token operator">=</span> encodedResource<span class="token punctuation">.</span><span class="token function">getResource</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token comment">// 使用Java提供的工具类解析</span>
            <span class="token class-name">InputSource</span> inputSource <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">InputSource</span><span class="token punctuation">(</span>inputStream<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 设置编码格式</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>encodedResource<span class="token punctuation">.</span><span class="token function">getEncoding</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                inputSource<span class="token punctuation">.</span><span class="token function">setEncoding</span><span class="token punctuation">(</span>encodedResource<span class="token punctuation">.</span><span class="token function">getEncoding</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token comment">// 加载BeanDefinitions</span>
            <span class="token keyword">return</span> <span class="token function">doLoadBeanDefinitions</span><span class="token punctuation">(</span>inputSource<span class="token punctuation">,</span> encodedResource<span class="token punctuation">.</span><span class="token function">getResource</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">finally</span> <span class="token punctuation">{</span>
            inputStream<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// ...略</span>
    <span class="token keyword">finally</span> <span class="token punctuation">{</span>
        currentResources<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>encodedResource<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>currentResources<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>resourcesCurrentlyBeingLoaded<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br></div></div><p>进入 doLoadBeanDefinitions() 方法，该方法首先将 inputSource 转为 Document 对象，然后再转为 BeanDefinitions 对象</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">int</span> <span class="token function">doLoadBeanDefinitions</span><span class="token punctuation">(</span><span class="token class-name">InputSource</span> inputSource<span class="token punctuation">,</span> <span class="token class-name">Resource</span> resource<span class="token punctuation">)</span>
			<span class="token keyword">throws</span> <span class="token class-name">BeanDefinitionStoreException</span> <span class="token punctuation">{</span>

    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token comment">// 将输入流转化成Document对象</span>
        <span class="token class-name">Document</span> doc <span class="token operator">=</span> <span class="token function">doLoadDocument</span><span class="token punctuation">(</span>inputSource<span class="token punctuation">,</span> resource<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 开始解析Bean，返回注册bean标签的个数</span>
        <span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token function">registerBeanDefinitions</span><span class="token punctuation">(</span>doc<span class="token punctuation">,</span> resource<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>logger<span class="token punctuation">.</span><span class="token function">isDebugEnabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            logger<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">&quot;Loaded &quot;</span> <span class="token operator">+</span> count <span class="token operator">+</span> <span class="token string">&quot; bean definitions from &quot;</span> <span class="token operator">+</span> resource<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> count<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// ...异常略</span>
    <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">BeanDefinitionStoreException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">SAXParseException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">SAXException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ParserConfigurationException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br></div></div><p>进入 registerBeanDefinition 方法，可以得知 documentReader.registerBeanDefinitions() 方法才是核心的封装 BeanDefinitions 对象的方法</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">registerBeanDefinitions</span><span class="token punctuation">(</span><span class="token class-name">Document</span> doc<span class="token punctuation">,</span> <span class="token class-name">Resource</span> resource<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeanDefinitionStoreException</span> <span class="token punctuation">{</span>
    <span class="token class-name">BeanDefinitionDocumentReader</span> documentReader <span class="token operator">=</span> <span class="token function">createBeanDefinitionDocumentReader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> countBefore <span class="token operator">=</span> <span class="token function">getRegistry</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getBeanDefinitionCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 解析Bean，因为 BeanDefinitionDocumentReader 是接口，所以应该去找它的实现</span>
    documentReader<span class="token punctuation">.</span><span class="token function">registerBeanDefinitions</span><span class="token punctuation">(</span>doc<span class="token punctuation">,</span> <span class="token function">createReaderContext</span><span class="token punctuation">(</span>resource<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 返回bean的个数</span>
    <span class="token keyword">return</span> <span class="token function">getRegistry</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getBeanDefinitionCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> countBefore<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>进入 registerBeanDefinitions() 方法的实现</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">registerBeanDefinitions</span><span class="token punctuation">(</span><span class="token class-name">Document</span> doc<span class="token punctuation">,</span> <span class="token class-name">XmlReaderContext</span> readerContext<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>readerContext <span class="token operator">=</span> readerContext<span class="token punctuation">;</span>
    <span class="token comment">// 解析Bean</span>
    <span class="token function">doRegisterBeanDefinitions</span><span class="token punctuation">(</span>doc<span class="token punctuation">.</span><span class="token function">getDocumentElement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>进入 doRegisterBeanDefinitions() 方法，该方法主要是处理 beans 标签的，首先读取了 包含 profile 属性的 beans 标签（profiles 属性可实现多环境配置），接着重头戏是 parseBeanDefinitions() 方法</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">doRegisterBeanDefinitions</span><span class="token punctuation">(</span><span class="token class-name">Element</span> root<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">BeanDefinitionParserDelegate</span> parent <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>delegate<span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>delegate <span class="token operator">=</span> <span class="token function">createDelegate</span><span class="token punctuation">(</span><span class="token function">getReaderContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> root<span class="token punctuation">,</span> parent<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>delegate<span class="token punctuation">.</span><span class="token function">isDefaultNamespace</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 解析bean标签中包含profile属性的标签</span>
        <span class="token comment">// profile属性可以设置Spring多环境配置</span>
        <span class="token class-name">String</span> profileSpec <span class="token operator">=</span> root<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>PROFILE_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">hasText</span><span class="token punctuation">(</span>profileSpec<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// ...略</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token function">preProcessXml</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 解析Bean</span>
    <span class="token function">parseBeanDefinitions</span><span class="token punctuation">(</span>root<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>delegate<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">postProcessXml</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">this</span><span class="token punctuation">.</span>delegate <span class="token operator">=</span> parent<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><p><strong>profile 标签实现多环境</strong>（Spring 中多使用在 Spring MVC 中实现多环境配置）</p> <p>applicationContext.xml</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token prolog">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>beans</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.springframework.org/schema/beans<span class="token punctuation">&quot;</span></span>
       <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">&quot;</span></span>
       <span class="token attr-name"><span class="token namespace">xsi:</span>schemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd<span class="token punctuation">&quot;</span></span>
<span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>beans</span> <span class="token attr-name">profile</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>dev<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>user1<span class="token punctuation">&quot;</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>com.yyh.pojo.User<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>username<span class="token punctuation">&quot;</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>admin<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>password<span class="token punctuation">&quot;</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>123456<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>bean</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>beans</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>beans</span> <span class="token attr-name">profile</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>prod<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>user2<span class="token punctuation">&quot;</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>com.yyh.pojo.User<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>username<span class="token punctuation">&quot;</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>user<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>password<span class="token punctuation">&quot;</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>123<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>bean</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>beans</span><span class="token punctuation">&gt;</span></span>
    
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>beans</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br></div></div><p>web.xml</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">web-app</span> <span class="token name">PUBLIC</span>
 <span class="token string">&quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot;</span>
 <span class="token string">&quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot;</span> <span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>web-app</span><span class="token punctuation">&gt;</span></span>

  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>context-param</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>param-name</span><span class="token punctuation">&gt;</span></span>Spring.profiles.active<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>param-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>param-value</span><span class="token punctuation">&gt;</span></span>dev<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>param-value</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>context-param</span><span class="token punctuation">&gt;</span></span>
  
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>web-app</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p>进入 parseBeanDefinitions() 方法，该方法会解析默认标签和属性和自定义标签和属性，默认标签、属性就是 Spring 的 beans、bean、import、alias 等标签；自定义标签指的是通过引入命名空间的标签，比如 Spring MVC 的 &lt;context:property-placeholder/&gt; 标签</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">parseBeanDefinitions</span><span class="token punctuation">(</span><span class="token class-name">Element</span> root<span class="token punctuation">,</span> <span class="token class-name">BeanDefinitionParserDelegate</span> delegate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>delegate<span class="token punctuation">.</span><span class="token function">isDefaultNamespace</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 解析XML中的空格、换行、标签这些元素</span>
        <span class="token class-name">NodeList</span> nl <span class="token operator">=</span> root<span class="token punctuation">.</span><span class="token function">getChildNodes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> nl<span class="token punctuation">.</span><span class="token function">getLength</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">Node</span> node <span class="token operator">=</span> nl<span class="token punctuation">.</span><span class="token function">item</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>node <span class="token keyword">instanceof</span> <span class="token class-name">Element</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">Element</span> ele <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">Element</span><span class="token punctuation">)</span> node<span class="token punctuation">;</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>delegate<span class="token punctuation">.</span><span class="token function">isDefaultNamespace</span><span class="token punctuation">(</span>ele<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token comment">// 解析默认标签</span>
                    <span class="token comment">// bean、import、alias、beans这些Spring配置文件包含的</span>
                    <span class="token function">parseDefaultElement</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> delegate<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
                <span class="token keyword">else</span> <span class="token punctuation">{</span>
                    <span class="token comment">// 解析自定义标签</span>
                    <span class="token comment">// 需要通过命名空间引入的，如Spring MVC的&lt;context:component-scan/&gt;</span>
                    delegate<span class="token punctuation">.</span><span class="token function">parseCustomElement</span><span class="token punctuation">(</span>ele<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">else</span> <span class="token punctuation">{</span>
        delegate<span class="token punctuation">.</span><span class="token function">parseCustomElement</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br></div></div><p>进入 parseDefaultElement() 方法</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">parseDefaultElement</span><span class="token punctuation">(</span><span class="token class-name">Element</span> ele<span class="token punctuation">,</span> <span class="token class-name">BeanDefinitionParserDelegate</span> delegate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>delegate<span class="token punctuation">.</span><span class="token function">nodeNameEquals</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> IMPORT_ELEMENT<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// import标签</span>
        <span class="token function">importBeanDefinitionResource</span><span class="token punctuation">(</span>ele<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>delegate<span class="token punctuation">.</span><span class="token function">nodeNameEquals</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> ALIAS_ELEMENT<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// alias标签</span>
        <span class="token function">processAliasRegistration</span><span class="token punctuation">(</span>ele<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>delegate<span class="token punctuation">.</span><span class="token function">nodeNameEquals</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> BEAN_ELEMENT<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// bean标签</span>
        <span class="token function">processBeanDefinition</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> delegate<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>delegate<span class="token punctuation">.</span><span class="token function">nodeNameEquals</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> NESTED_BEANS_ELEMENT<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 内置的beans标签</span>
        <span class="token function">doRegisterBeanDefinitions</span><span class="token punctuation">(</span>ele<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>主要看 Spring 是如何解析 bean 标签的，所以进入 processBeanDefinition() 方法。该方法使用 BeanDefinitionHolder 对 bean 标签进行了封装，其中考虑了在 bean 标签中可能会包含自定义标签的情况，所以如果 bean 标签内包含了自定义标签， Spring 就会再次包装 bdHolder 对象，最后注册 BeanDefinitions。如果 注册成功， Spring 就会发生注册成功的信息给容器，不过 Spring 目前还没有相好如何去实习该通知方法的逻辑，Spring Boot 中有实现了这个方法的逻辑，当然这是以后需要讨论的，目前不展开讨论</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">processBeanDefinition</span><span class="token punctuation">(</span><span class="token class-name">Element</span> ele<span class="token punctuation">,</span> <span class="token class-name">BeanDefinitionParserDelegate</span> delegate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 将Element对象封装成BeanDefinitionHolder对象</span>
    <span class="token comment">// BDH对象其实就是多了beanName、aliases</span>
    <span class="token class-name">BeanDefinitionHolder</span> bdHolder <span class="token operator">=</span> delegate<span class="token punctuation">.</span><span class="token function">parseBeanDefinitionElement</span><span class="token punctuation">(</span>ele<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>bdHolder <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 如果Bean标签内包含自定义标签，需要再装饰一层</span>
        bdHolder <span class="token operator">=</span> delegate<span class="token punctuation">.</span><span class="token function">decorateBeanDefinitionIfRequired</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> bdHolder<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token comment">// 真正的读取BeanDefinition的方法</span>
            <span class="token class-name">BeanDefinitionReaderUtils</span><span class="token punctuation">.</span><span class="token function">registerBeanDefinition</span><span class="token punctuation">(</span>bdHolder<span class="token punctuation">,</span> <span class="token function">getReaderContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getRegistry</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">BeanDefinitionStoreException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token function">getReaderContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">&quot;Failed to register bean definition with name '&quot;</span> <span class="token operator">+</span>
                                     bdHolder<span class="token punctuation">.</span><span class="token function">getBeanName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;'&quot;</span><span class="token punctuation">,</span> ele<span class="token punctuation">,</span> ex<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 发送注册事件</span>
        <span class="token comment">// Spring中并没有实现该方法的逻辑</span>
        <span class="token function">getReaderContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fireComponentRegistered</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">BeanComponentDefinition</span><span class="token punctuation">(</span>bdHolder<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><p>先进入 parseBeanDefinitionElement() 看看方法的逻辑实现</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Nullable</span>
<span class="token keyword">public</span> <span class="token class-name">BeanDefinitionHolder</span> <span class="token function">parseBeanDefinitionElement</span><span class="token punctuation">(</span><span class="token class-name">Element</span> ele<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token function">parseBeanDefinitionElement</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Nullable</span>
<span class="token keyword">public</span> <span class="token class-name">BeanDefinitionHolder</span> <span class="token function">parseBeanDefinitionElement</span><span class="token punctuation">(</span><span class="token class-name">Element</span> ele<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">BeanDefinition</span> containingBean<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">String</span> id <span class="token operator">=</span> ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>ID_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// bean的id属性</span>
    <span class="token class-name">String</span> nameAttr <span class="token operator">=</span> ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>NAME_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// bean的name属性</span>
	<span class="token comment">// bean别名，如果bean设置了多个别名，存进List中</span>
    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> aliases <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>nameAttr<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 支持  ,;空格  这三种分割方式</span>
        <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> nameArr <span class="token operator">=</span> <span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">tokenizeToStringArray</span><span class="token punctuation">(</span>nameAttr<span class="token punctuation">,</span> MULTI_VALUE_ATTRIBUTE_DELIMITERS<span class="token punctuation">)</span><span class="token punctuation">;</span>
        aliases<span class="token punctuation">.</span><span class="token function">addAll</span><span class="token punctuation">(</span><span class="token class-name">Arrays</span><span class="token punctuation">.</span><span class="token function">asList</span><span class="token punctuation">(</span>nameArr<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
	
    <span class="token class-name">String</span> beanName <span class="token operator">=</span> id<span class="token punctuation">;</span>
    <span class="token comment">// 如果bean标签没有id属性，将第一个别名赋值给beanName</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">hasText</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>aliases<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        beanName <span class="token operator">=</span> aliases<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>logger<span class="token punctuation">.</span><span class="token function">isTraceEnabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// ...日志略</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    
	<span class="token comment">// 如果委托类为null，就校验bean的id或者别名是否是唯一的</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>containingBean <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 验证指定的bean名称和别名在bean元素嵌套的当前级别内是否已经被使用</span>
        <span class="token function">checkNameUniqueness</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> aliases<span class="token punctuation">,</span> ele<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
	<span class="token comment">// 解析Bean元素</span>
    <span class="token class-name">AbstractBeanDefinition</span> beanDefinition <span class="token operator">=</span> <span class="token function">parseBeanDefinitionElement</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> containingBean<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>beanDefinition <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 如果没有id</span>
        <span class="token comment">// 上面的beanName已经有内容了，为什么还会判断id为null呢？</span>
        <span class="token comment">// 是因为可能有种情况，bean标签内id和name都没有填，只填class值的情况</span>
        <span class="token comment">// 此时Spring就会自动生成一个beanName</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">hasText</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">try</span> <span class="token punctuation">{</span>
                <span class="token comment">// 有委托Bean的情况</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>containingBean <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    beanName <span class="token operator">=</span> <span class="token class-name">BeanDefinitionReaderUtils</span><span class="token punctuation">.</span><span class="token function">generateBeanName</span><span class="token punctuation">(</span>
                        beanDefinition<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>readerContext<span class="token punctuation">.</span><span class="token function">getRegistry</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
                <span class="token keyword">else</span> <span class="token punctuation">{</span>
                    beanName <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>readerContext<span class="token punctuation">.</span><span class="token function">generateBeanName</span><span class="token punctuation">(</span>beanDefinition<span class="token punctuation">)</span><span class="token punctuation">;</span>
                    
                    <span class="token class-name">String</span> beanClassName <span class="token operator">=</span> beanDefinition<span class="token punctuation">.</span><span class="token function">getBeanClassName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token keyword">if</span> <span class="token punctuation">(</span>beanClassName <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span>
                        beanName<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span>beanClassName<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> beanName<span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> beanClassName<span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
                        <span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>readerContext<span class="token punctuation">.</span><span class="token function">getRegistry</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isBeanNameInUse</span><span class="token punctuation">(</span>beanClassName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        aliases<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>beanClassName<span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span>
                <span class="token punctuation">}</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>logger<span class="token punctuation">.</span><span class="token function">isTraceEnabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token comment">// ...日志略</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">// ...异常略</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> aliasesArray <span class="token operator">=</span> <span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">toStringArray</span><span class="token punctuation">(</span>aliases<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">BeanDefinitionHolder</span><span class="token punctuation">(</span>beanDefinition<span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> aliasesArray<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br><span class="line-number">62</span><br><span class="line-number">63</span><br><span class="line-number">64</span><br><span class="line-number">65</span><br><span class="line-number">66</span><br><span class="line-number">67</span><br><span class="line-number">68</span><br><span class="line-number">69</span><br></div></div><p>查看 parseBeanDefinitionElement() 的实现</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Nullable</span>
<span class="token keyword">public</span> <span class="token class-name">AbstractBeanDefinition</span> <span class="token function">parseBeanDefinitionElement</span><span class="token punctuation">(</span>
      <span class="token class-name">Element</span> ele<span class="token punctuation">,</span> <span class="token class-name">String</span> beanName<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">BeanDefinition</span> containingBean<span class="token punctuation">)</span> <span class="token punctuation">{</span>

   <span class="token keyword">this</span><span class="token punctuation">.</span>parseState<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">BeanEntry</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

   <span class="token class-name">String</span> className <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span>CLASS_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 解析class属性</span>
      className <span class="token operator">=</span> ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>CLASS_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   <span class="token class-name">String</span> parent <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span>PARENT_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//解析parent属性</span>
      parent <span class="token operator">=</span> ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>PARENT_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token keyword">try</span> <span class="token punctuation">{</span>
      <span class="token class-name">AbstractBeanDefinition</span> bd <span class="token operator">=</span> <span class="token function">createBeanDefinition</span><span class="token punctuation">(</span>className<span class="token punctuation">,</span> parent<span class="token punctuation">)</span><span class="token punctuation">;</span>

       <span class="token comment">// 解析bean标签中的init-method、destroy-method、autowire、scope等属性</span>
      <span class="token function">parseBeanDefinitionAttributes</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> containingBean<span class="token punctuation">,</span> bd<span class="token punctuation">)</span><span class="token punctuation">;</span>
      bd<span class="token punctuation">.</span><span class="token function">setDescription</span><span class="token punctuation">(</span><span class="token class-name">DomUtils</span><span class="token punctuation">.</span><span class="token function">getChildElementValueByTagName</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> DESCRIPTION_ELEMENT<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	  <span class="token comment">// 解析&lt;meta/&gt;标签</span>
      <span class="token function">parseMetaElements</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> bd<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">// 解析&lt;lookup-method/&gt;标签</span>
      <span class="token function">parseLookupOverrideSubElements</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> bd<span class="token punctuation">.</span><span class="token function">getMethodOverrides</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">// 解析&lt;replaced-method/&gt;标签</span>
      <span class="token function">parseReplacedMethodSubElements</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> bd<span class="token punctuation">.</span><span class="token function">getMethodOverrides</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	  <span class="token comment">// 解析&lt;constructor-arg/&gt;标签</span>
      <span class="token function">parseConstructorArgElements</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> bd<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">// 解析&lt;property/&gt;标签</span>
      <span class="token function">parsePropertyElements</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> bd<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">// 解析&lt;qualifier/&gt;标签</span>
      <span class="token function">parseQualifierElements</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> bd<span class="token punctuation">)</span><span class="token punctuation">;</span>

      bd<span class="token punctuation">.</span><span class="token function">setResource</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>readerContext<span class="token punctuation">.</span><span class="token function">getResource</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      bd<span class="token punctuation">.</span><span class="token function">setSource</span><span class="token punctuation">(</span><span class="token function">extractSource</span><span class="token punctuation">(</span>ele<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

      <span class="token keyword">return</span> bd<span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ClassNotFoundException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// ...异常略</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">NoClassDefFoundError</span> err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// ...异常略</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// ...异常略</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">finally</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>parseState<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br></div></div><p>解析bean标签属性的方法 parseBeanDefinitionAttributes()</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token class-name">AbstractBeanDefinition</span> <span class="token function">parseBeanDefinitionAttributes</span><span class="token punctuation">(</span><span class="token class-name">Element</span> ele<span class="token punctuation">,</span> <span class="token class-name">String</span> beanName<span class="token punctuation">,</span>
      <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">BeanDefinition</span> containingBean<span class="token punctuation">,</span> <span class="token class-name">AbstractBeanDefinition</span> bd<span class="token punctuation">)</span> <span class="token punctuation">{</span>

   <span class="token keyword">if</span> <span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span>SINGLETON_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//singleton，不过已经废弃了，官方推荐使用scope属性</span>
      <span class="token function">error</span><span class="token punctuation">(</span><span class="token string">&quot;Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration&quot;</span><span class="token punctuation">,</span> ele<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span>SCOPE_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//scope</span>
      bd<span class="token punctuation">.</span><span class="token function">setScope</span><span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>SCOPE_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>containingBean <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Take default from containing bean in case of an inner bean definition.</span>
      bd<span class="token punctuation">.</span><span class="token function">setScope</span><span class="token punctuation">(</span>containingBean<span class="token punctuation">.</span><span class="token function">getScope</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token keyword">if</span> <span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span>ABSTRACT_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//abstarct</span>
      bd<span class="token punctuation">.</span><span class="token function">setAbstract</span><span class="token punctuation">(</span>TRUE_VALUE<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>ABSTRACT_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token class-name">String</span> lazyInit <span class="token operator">=</span> ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>LAZY_INIT_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//lazy-init</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDefaultValue</span><span class="token punctuation">(</span>lazyInit<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      lazyInit <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>defaults<span class="token punctuation">.</span><span class="token function">getLazyInit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   bd<span class="token punctuation">.</span><span class="token function">setLazyInit</span><span class="token punctuation">(</span>TRUE_VALUE<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>lazyInit<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

   <span class="token class-name">String</span> autowire <span class="token operator">=</span> ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>AUTOWIRE_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//autowire</span>
   bd<span class="token punctuation">.</span><span class="token function">setAutowireMode</span><span class="token punctuation">(</span><span class="token function">getAutowireMode</span><span class="token punctuation">(</span>autowire<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

   <span class="token keyword">if</span> <span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span>DEPENDS_ON_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token class-name">String</span> dependsOn <span class="token operator">=</span> ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>DEPENDS_ON_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//depends-on</span>
      bd<span class="token punctuation">.</span><span class="token function">setDependsOn</span><span class="token punctuation">(</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">tokenizeToStringArray</span><span class="token punctuation">(</span>dependsOn<span class="token punctuation">,</span> MULTI_VALUE_ATTRIBUTE_DELIMITERS<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token class-name">String</span> autowireCandidate <span class="token operator">=</span> ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>AUTOWIRE_CANDIDATE_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//autowire-candidate</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isDefaultValue</span><span class="token punctuation">(</span>autowireCandidate<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token class-name">String</span> candidatePattern <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>defaults<span class="token punctuation">.</span><span class="token function">getAutowireCandidates</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>candidatePattern <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
         <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> patterns <span class="token operator">=</span> <span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">commaDelimitedListToStringArray</span><span class="token punctuation">(</span>candidatePattern<span class="token punctuation">)</span><span class="token punctuation">;</span>
         bd<span class="token punctuation">.</span><span class="token function">setAutowireCandidate</span><span class="token punctuation">(</span><span class="token class-name">PatternMatchUtils</span><span class="token punctuation">.</span><span class="token function">simpleMatch</span><span class="token punctuation">(</span>patterns<span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">else</span> <span class="token punctuation">{</span>
      bd<span class="token punctuation">.</span><span class="token function">setAutowireCandidate</span><span class="token punctuation">(</span>TRUE_VALUE<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>autowireCandidate<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token keyword">if</span> <span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span>PRIMARY_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//primary</span>
      bd<span class="token punctuation">.</span><span class="token function">setPrimary</span><span class="token punctuation">(</span>TRUE_VALUE<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>PRIMARY_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token keyword">if</span> <span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span>INIT_METHOD_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//init-method</span>
      <span class="token class-name">String</span> initMethodName <span class="token operator">=</span> ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>INIT_METHOD_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">;</span>
      bd<span class="token punctuation">.</span><span class="token function">setInitMethodName</span><span class="token punctuation">(</span>initMethodName<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>defaults<span class="token punctuation">.</span><span class="token function">getInitMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      bd<span class="token punctuation">.</span><span class="token function">setInitMethodName</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>defaults<span class="token punctuation">.</span><span class="token function">getInitMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      bd<span class="token punctuation">.</span><span class="token function">setEnforceInitMethod</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token keyword">if</span> <span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span>DESTROY_METHOD_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//destroy-method</span>
      <span class="token class-name">String</span> destroyMethodName <span class="token operator">=</span> ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>DESTROY_METHOD_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">;</span>
      bd<span class="token punctuation">.</span><span class="token function">setDestroyMethodName</span><span class="token punctuation">(</span>destroyMethodName<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>defaults<span class="token punctuation">.</span><span class="token function">getDestroyMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      bd<span class="token punctuation">.</span><span class="token function">setDestroyMethodName</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>defaults<span class="token punctuation">.</span><span class="token function">getDestroyMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      bd<span class="token punctuation">.</span><span class="token function">setEnforceDestroyMethod</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token keyword">if</span> <span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span>FACTORY_METHOD_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//factory-method</span>
      bd<span class="token punctuation">.</span><span class="token function">setFactoryMethodName</span><span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>FACTORY_METHOD_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span>FACTORY_BEAN_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//factory-bean</span>
      bd<span class="token punctuation">.</span><span class="token function">setFactoryBeanName</span><span class="token punctuation">(</span>ele<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>FACTORY_BEAN_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token keyword">return</span> bd<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br><span class="line-number">62</span><br><span class="line-number">63</span><br><span class="line-number">64</span><br><span class="line-number">65</span><br><span class="line-number">66</span><br><span class="line-number">67</span><br><span class="line-number">68</span><br><span class="line-number">69</span><br><span class="line-number">70</span><br><span class="line-number">71</span><br><span class="line-number">72</span><br><span class="line-number">73</span><br><span class="line-number">74</span><br><span class="line-number">75</span><br></div></div><p>ok，了解完 parseBeanDefinitionElement() 方法是解析 XML 标签内容返回 BeanDefinitionHolder 对象之后，我们来看一下 Spring 如何将 BDH 对象封装为 BeanDefinition 对象的，回到 processBeanDefinition() 方法，进入 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">registerBeanDefinition</span><span class="token punctuation">(</span>
      <span class="token class-name">BeanDefinitionHolder</span> definitionHolder<span class="token punctuation">,</span> <span class="token class-name">BeanDefinitionRegistry</span> registry<span class="token punctuation">)</span>
      <span class="token keyword">throws</span> <span class="token class-name">BeanDefinitionStoreException</span> <span class="token punctuation">{</span>

   <span class="token comment">// 获取beanName，前面生成的BHD对象肯定是包含beanName的，所以可以直接get到</span>
   <span class="token class-name">String</span> beanName <span class="token operator">=</span> definitionHolder<span class="token punctuation">.</span><span class="token function">getBeanName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token comment">// 注册BeanDefinition对象</span>
   registry<span class="token punctuation">.</span><span class="token function">registerBeanDefinition</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> definitionHolder<span class="token punctuation">.</span><span class="token function">getBeanDefinition</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

   <span class="token comment">// 设置别名，如果有的话</span>
   <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> aliases <span class="token operator">=</span> definitionHolder<span class="token punctuation">.</span><span class="token function">getAliases</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span>aliases <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> alias <span class="token operator">:</span> aliases<span class="token punctuation">)</span> <span class="token punctuation">{</span>
         registry<span class="token punctuation">.</span><span class="token function">registerAlias</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> alias<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
   <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>查看 registerBeanDefinition() 方法，选择 DefaultListableBeanFactory 的实现</p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210911201035608.png" alt="image-20210911201035608"></p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">BeanDefinition</span><span class="token punctuation">&gt;</span></span> beanDefinitionMap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ConcurrentHashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token number">256</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> beanDefinitionNames <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token number">256</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">registerBeanDefinition</span><span class="token punctuation">(</span><span class="token class-name">String</span> beanName<span class="token punctuation">,</span> <span class="token class-name">BeanDefinition</span> beanDefinition<span class="token punctuation">)</span>
      <span class="token keyword">throws</span> <span class="token class-name">BeanDefinitionStoreException</span> <span class="token punctuation">{</span>

   <span class="token comment">// ...校验略</span>

   <span class="token class-name">BeanDefinition</span> existingDefinition <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>beanDefinitionMap<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span>existingDefinition <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// ...如果BeanDefinition已经被注册，这种情况不常见，略</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">hasBeanCreationStarted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
         <span class="token comment">// 启动阶段不能注册</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">else</span> <span class="token punctuation">{</span>
         <span class="token comment">// 正常启动</span>
         <span class="token comment">// 将beanDefinition和beanName分别存进Map和List</span>
         <span class="token keyword">this</span><span class="token punctuation">.</span>beanDefinitionMap<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> beanDefinition<span class="token punctuation">)</span><span class="token punctuation">;</span>
         <span class="token keyword">this</span><span class="token punctuation">.</span>beanDefinitionNames<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
         <span class="token function">removeManualSingletonName</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>frozenBeanDefinitionNames <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   <span class="token keyword">if</span> <span class="token punctuation">(</span>existingDefinition <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">||</span> <span class="token function">containsSingleton</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">resetBeanDefinition</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isConfigurationFrozen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">clearByTypeCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br></div></div><p>🆗已经完成了 Spring 对默认标签的解析源码阅读，下面我们来探讨 Spring 是如何对自定义标签进行解析的</p> <h3 id="_2-3-spring-如何解析自定义标签"><a href="#_2-3-spring-如何解析自定义标签" class="header-anchor">#</a> 2.3 Spring 如何解析自定义标签？</h3> <p>在阅读 Spring 解析自定义标签之前，我们不妨先自己实现一个自定义的标签</p> <p>再绕个弯子，在实现自己的自定义标签之前，我们可以先粗略看一下 Spring MVC 的 Spring 标签是如何实现的</p> <p><strong>Spring MVC 中自定义标签的实现步骤粗略理解</strong></p> <p>在 Spring 整合 Spring MVC 的时候，我们都是在配置文件中加入 Spring MVC 的约束文件，让其能够对标签属性进行约束；而能够对标签属性进行约束的文件是放在 spring-webmvc\src\main\resources\META-INF 下的 spring.handlers 和 spring.schemas 文件</p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210911221713160.png" alt="image-20210911221713160"></p> <p>spring.handlers</p> <p>可以看出 spring.handlers 文件是使用 MvcNamespaceHandler 这个类去实现约束的</p> <div class="language-properties line-numbers-mode"><pre class="language-properties"><code><span class="token attr-name">http\://www.springframework.org/schema/mvc</span><span class="token punctuation">=</span><span class="token attr-value">org.springframework.web.servlet.config.MvcNamespaceHandler</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>spring.schemas</p> <p>spring.schemas 则是定义了各种 xsd 约束文件</p> <div class="language-properties line-numbers-mode"><pre class="language-properties"><code><span class="token attr-name">http\://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">http\://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">http\://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">http\://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">http\://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">http\://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">http\://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">http\://www.springframework.org/schema/mvc/spring-mvc.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">https\://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">https\://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">https\://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">https\://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">https\://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">https\://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">https\://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
<span class="token attr-name">https\://www.springframework.org/schema/mvc/spring-mvc.xsd</span><span class="token punctuation">=</span><span class="token attr-value">org/springframework/web/servlet/config/spring-mvc.xsd</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><p>MvcNamespaceHandler</p> <p>MvcNamespaceHandler 这个类首先是覆写了 init() 这个方法来实现命名空间的初始化，然后在里面使用 BeanDefinitionParser 解析了各种 Parser</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MvcNamespaceHandler</span> <span class="token keyword">extends</span> <span class="token class-name">NamespaceHandlerSupport</span> <span class="token punctuation">{</span>

   <span class="token annotation punctuation">@Override</span>
   <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;annotation-driven&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">AnnotationDrivenBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;default-servlet-handler&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">DefaultServletHandlerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;interceptors&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">InterceptorsBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;resources&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ResourcesBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;view-controller&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ViewControllerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;redirect-view-controller&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ViewControllerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;status-controller&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ViewControllerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;view-resolvers&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ViewResolversBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;tiles-configurer&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">TilesConfigurerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;freemarker-configurer&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">FreeMarkerConfigurerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;groovy-configurer&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">GroovyMarkupConfigurerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;script-template-configurer&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ScriptTemplateConfigurerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;cors&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">CorsBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><p>随便点进去一个 Paser，可以看到它实现了 BeanDefinitionParser 接口</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">class</span> <span class="token class-name">AnnotationDrivenBeanDefinitionParser</span> <span class="token keyword">implements</span> <span class="token class-name">BeanDefinitionParser</span> <span class="token punctuation">{</span>
    <span class="token comment">// ...代码略</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p><strong>自定义标签的实现</strong></p> <blockquote><p>在以上的分析可知，自定义标签必须要准备的内容有：</p> <p>META-INF 下必须要有 spring.handlers 和 spring.schemas 文件</p> <ol><li>spring.handlers：存自定义的 NamespaceHandler，需要继承 NamespaceHandlerSupport 类，然后覆写 init() 方法，在 init() 方法中 使用 registerBeanDefinitionParser() 方法注册自定义的 Parser，而自定义的 Parser 需要实现 BeanDefinitionParser 接口，而我们直接继承 AbstractSingleBeanDefinitionParser 类覆写 doParse() 方法和 getBeanClass() 方法也是可以的</li> <li>spring.schemas：编写 xsd 约束文件</li></ol></blockquote> <ol><li>xsd 约束文件</li></ol> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token prolog">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;</span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>schema</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.w3.org/2001/XMLSchema<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">targetNamespace</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.yyh.com/schema/user<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name"><span class="token namespace">xmlns:</span>tns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.yyh.com/schema/user<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">elementFormDefault</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>qualified<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>element</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>user<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>complexType</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>attribute</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>id<span class="token punctuation">&quot;</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>string<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>attribute</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>username<span class="token punctuation">&quot;</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>string<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>attribute</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>password<span class="token punctuation">&quot;</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>string<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>complexType</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>element</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>schema</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>spring.schemas</p> <div class="language-properties line-numbers-mode"><pre class="language-properties"><code><span class="token attr-name">http\://www.yyh.com/schema/user/user-1.0.xsd</span><span class="token punctuation">=</span><span class="token attr-value">META-INF/user-1.0.xsd</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>spring.handlers</p> <div class="language-properties line-numbers-mode"><pre class="language-properties"><code><span class="token attr-name">http\://www.yyh.com/schema/user</span><span class="token punctuation">=</span><span class="token attr-value">com.yyh.config.UserNamespaceHandler</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>applicationContext.xml</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token prolog">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>beans</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.springframework.org/schema/beans<span class="token punctuation">&quot;</span></span>
       <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">&quot;</span></span>
       <span class="token attr-name"><span class="token namespace">xmlns:</span>yyh</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.yyh.com/schema/user<span class="token punctuation">&quot;</span></span>
       <span class="token attr-name"><span class="token namespace">xsi:</span>schemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.yyh.com/schema/user
       http://www.yyh.com/schema/user/user-1.0.xsd<span class="token punctuation">&quot;</span></span>
<span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">yyh:</span>user</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>myuser<span class="token punctuation">&quot;</span></span> <span class="token attr-name">username</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>admin<span class="token punctuation">&quot;</span></span> <span class="token attr-name">password</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>123123<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>beans</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><p>UserNamespaceHandler.java</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserNamespaceHandler</span> <span class="token keyword">extends</span> <span class="token class-name">NamespaceHandlerSupport</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">registerBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token string">&quot;user&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">UserBeanDefinitionParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>UserBeanDefinitionParser.java</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserBeanDefinitionParser</span> <span class="token keyword">extends</span> <span class="token class-name">AbstractSingleBeanDefinitionParser</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">protected</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> <span class="token function">getBeanClass</span><span class="token punctuation">(</span><span class="token class-name">Element</span> element<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token class-name">User</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">doParse</span><span class="token punctuation">(</span><span class="token class-name">Element</span> element<span class="token punctuation">,</span> <span class="token class-name">BeanDefinitionBuilder</span> builder<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        builder<span class="token punctuation">.</span><span class="token function">addPropertyValue</span><span class="token punctuation">(</span><span class="token string">&quot;username&quot;</span><span class="token punctuation">,</span> element<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        builder<span class="token punctuation">.</span><span class="token function">addPropertyValue</span><span class="token punctuation">(</span><span class="token string">&quot;password&quot;</span><span class="token punctuation">,</span> element<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;password&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p><strong>Spring 解析自定义标签</strong></p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">parseBeanDefinitions</span><span class="token punctuation">(</span><span class="token class-name">Element</span> root<span class="token punctuation">,</span> <span class="token class-name">BeanDefinitionParserDelegate</span> delegate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span>delegate<span class="token punctuation">.</span><span class="token function">isDefaultNamespace</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token class-name">NodeList</span> nl <span class="token operator">=</span> root<span class="token punctuation">.</span><span class="token function">getChildNodes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> nl<span class="token punctuation">.</span><span class="token function">getLength</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
         <span class="token class-name">Node</span> node <span class="token operator">=</span> nl<span class="token punctuation">.</span><span class="token function">item</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
         <span class="token keyword">if</span> <span class="token punctuation">(</span>node <span class="token keyword">instanceof</span> <span class="token class-name">Element</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">Element</span> ele <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">Element</span><span class="token punctuation">)</span> node<span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>delegate<span class="token punctuation">.</span><span class="token function">isDefaultNamespace</span><span class="token punctuation">(</span>ele<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
               <span class="token function">parseDefaultElement</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> delegate<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">else</span> <span class="token punctuation">{</span>
               <span class="token comment">// 主要研究这个</span>
               delegate<span class="token punctuation">.</span><span class="token function">parseCustomElement</span><span class="token punctuation">(</span>ele<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
         <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">else</span> <span class="token punctuation">{</span>
      delegate<span class="token punctuation">.</span><span class="token function">parseCustomElement</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br></div></div><p>进入 parseCustomElement() 方法</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Nullable</span>
<span class="token keyword">public</span> <span class="token class-name">BeanDefinition</span> <span class="token function">parseCustomElement</span><span class="token punctuation">(</span><span class="token class-name">Element</span> ele<span class="token punctuation">)</span> <span class="token punctuation">{</span>
   <span class="token keyword">return</span> <span class="token function">parseCustomElement</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Nullable</span>
<span class="token keyword">public</span> <span class="token class-name">BeanDefinition</span> <span class="token function">parseCustomElement</span><span class="token punctuation">(</span><span class="token class-name">Element</span> ele<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">BeanDefinition</span> containingBd<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 获取namespace</span>
   <span class="token class-name">String</span> namespaceUri <span class="token operator">=</span> <span class="token function">getNamespaceURI</span><span class="token punctuation">(</span>ele<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span>namespaceUri <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   <span class="token comment">// 解析url</span>
   <span class="token class-name">NamespaceHandler</span> handler <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>readerContext<span class="token punctuation">.</span><span class="token function">getNamespaceHandlerResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>namespaceUri<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span>handler <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">error</span><span class="token punctuation">(</span><span class="token string">&quot;Unable to locate Spring NamespaceHandler for XML schema namespace [&quot;</span> <span class="token operator">+</span> namespaceUri <span class="token operator">+</span> <span class="token string">&quot;]&quot;</span><span class="token punctuation">,</span> ele<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   <span class="token comment">// 解析标签</span>
   <span class="token keyword">return</span> handler<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>ele<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ParserContext</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>readerContext<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">,</span> containingBd<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br></div></div><p>进入 parse() 方法，选择 NamespaceHandlerSupport</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Override</span>
<span class="token annotation punctuation">@Nullable</span>
<span class="token keyword">public</span> <span class="token class-name">BeanDefinition</span> <span class="token function">parse</span><span class="token punctuation">(</span><span class="token class-name">Element</span> element<span class="token punctuation">,</span> <span class="token class-name">ParserContext</span> parserContext<span class="token punctuation">)</span> <span class="token punctuation">{</span>
   <span class="token class-name">BeanDefinitionParser</span> parser <span class="token operator">=</span> <span class="token function">findParserForElement</span><span class="token punctuation">(</span>element<span class="token punctuation">,</span> parserContext<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token keyword">return</span> <span class="token punctuation">(</span>parser <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">?</span> parser<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>element<span class="token punctuation">,</span> parserContext<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>继续进去 parse() 方法，随便选一个实现，我看 ComponentScan 的实现</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Override</span>
<span class="token annotation punctuation">@Nullable</span>
<span class="token keyword">public</span> <span class="token class-name">BeanDefinition</span> <span class="token function">parse</span><span class="token punctuation">(</span><span class="token class-name">Element</span> element<span class="token punctuation">,</span> <span class="token class-name">ParserContext</span> parserContext<span class="token punctuation">)</span> <span class="token punctuation">{</span>
   <span class="token class-name">String</span> basePackage <span class="token operator">=</span> element<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span>BASE_PACKAGE_ATTRIBUTE<span class="token punctuation">)</span><span class="token punctuation">;</span>
   basePackage <span class="token operator">=</span> parserContext<span class="token punctuation">.</span><span class="token function">getReaderContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getEnvironment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">resolvePlaceholders</span><span class="token punctuation">(</span>basePackage<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> basePackages <span class="token operator">=</span> <span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">tokenizeToStringArray</span><span class="token punctuation">(</span>basePackage<span class="token punctuation">,</span>
         <span class="token class-name">ConfigurableApplicationContext</span><span class="token punctuation">.</span>CONFIG_LOCATION_DELIMITERS<span class="token punctuation">)</span><span class="token punctuation">;</span>

   <span class="token comment">// Actually scan for bean definitions and register them.</span>
   <span class="token class-name">ClassPathBeanDefinitionScanner</span> scanner <span class="token operator">=</span> <span class="token function">configureScanner</span><span class="token punctuation">(</span>parserContext<span class="token punctuation">,</span> element<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">BeanDefinitionHolder</span><span class="token punctuation">&gt;</span></span> beanDefinitions <span class="token operator">=</span> scanner<span class="token punctuation">.</span><span class="token function">doScan</span><span class="token punctuation">(</span>basePackages<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token function">registerComponents</span><span class="token punctuation">(</span>parserContext<span class="token punctuation">.</span><span class="token function">getReaderContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanDefinitions<span class="token punctuation">,</span> element<span class="token punctuation">)</span><span class="token punctuation">;</span>

   <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>自定义标签的解析没什么好看的，直接过了！</p> <h3 id="_2-4-spring-ioc"><a href="#_2-4-spring-ioc" class="header-anchor">#</a> 2.4 Spring IOC</h3> <p><strong>2.4.1 Spring 中有多少种简单对象的创建的方式？</strong></p> <ol><li>简单对象的创建
<ol><li>直接使用 &lt;bean/&gt; 标签</li></ol></li> <li>复杂对象的创建
<ol><li>实现 FactoryBean 接口</li> <li>实例工厂</li> <li>静态工厂</li></ol></li></ol> <p><strong>2.4.2 Spring 有多少种注入方式？</strong></p> <ol><li>set 注入
<ol><li>String + 8 种基本数据类型的注入：&lt;value/&gt;</li> <li>数组、List、Set、Map、Properties 注入：&lt;list/&gt;、&lt;list/&gt;、&lt;set/&gt;、&lt;entry key=&quot;&quot; value=&quot;&quot;/&gt;、&lt;props/&gt;</li> <li>用户自定义类型注入：&lt;property/&gt; 中 注入 &lt;bean/&gt; 、或者 &lt;ref/&gt;</li></ol></li> <li>构造注入：&lt;constructor-arg/&gt;</li> <li>autowire 注入</li></ol> <p><strong>2.4.3 BeanNameAware 与 BeanFactoryAware 的使用场景</strong></p> <p>1）BeanNameAware 使用场景</p> <p>在编写系统日志的时候需要**获取 Spring Bean 工厂的 ID（beanName）**信息时</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token keyword">implements</span> <span class="token class-name">BeanNameAware</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> username<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> password<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> beanName<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setBeanName</span><span class="token punctuation">(</span><span class="token class-name">String</span> beanName<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>beanName <span class="token operator">=</span> beanName<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">showBeanName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;beanName = &quot;</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><p>2）BeanFactoryAware 使用场景</p> <p><strong>假设 userDao 是线程不安全的，如果想要保证程序访问的可靠性，该怎么做？</strong></p> <p>答：</p> <div class="language- extra-class"><pre><code>1. 加锁（不推荐，会降低程序的吞吐量）
2. 每个用户分配一个 bean（也就是将 bean 变成多实例的）
</code></pre></div><p>当一个 Bean 被注入到其他容器之后，Bean 如果是多实例的（prototype），此时多实例不会生效</p> <p>例：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>userDao<span class="token punctuation">&quot;</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>com.yyh.dao.impl.UserDaoImpl<span class="token punctuation">&quot;</span></span> <span class="token attr-name">scope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>prototype<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>userService<span class="token punctuation">&quot;</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>com.yyh.service.impl.UserServiceImpl<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>userDao<span class="token punctuation">&quot;</span></span> <span class="token attr-name">ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>userDao<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>bean</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserServiceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">UserService</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">UserDao</span> userDao<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setUserDao</span><span class="token punctuation">(</span><span class="token class-name">UserDao</span> userDao<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>userDao<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>userDao <span class="token operator">=</span> userDao<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name">User</span> user<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>userDao<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>可以发现多实例 bean 并没有生效</p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210914213109992.png" alt="image-20210914213109992"></p> <p>如何解决？</p> <p>使用 BeanFactoryAware 接口，然后使用 beanFactory 去获取 bean</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserServiceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">UserService</span><span class="token punctuation">,</span> <span class="token class-name">BeanFactoryAware</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">BeanFactory</span> beanFactory<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name">User</span> user<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">UserDao</span> userDao <span class="token operator">=</span> beanFactory<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token string">&quot;userDao&quot;</span><span class="token punctuation">,</span> <span class="token class-name">UserDao</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>userDao<span class="token punctuation">)</span><span class="token punctuation">;</span>
        userDao<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setBeanFactory</span><span class="token punctuation">(</span><span class="token class-name">BeanFactory</span> beanFactory<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>beanFactory <span class="token operator">=</span> beanFactory<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>此时可以发现多实例 bean 生效了</p> <p><img src="https://gitee.com/YanHui-Yang/blog-img/raw/master/img/image-20210914213424447.png" alt="image-20210914213424447"></p></div></div> <div class="page-edit"><div class="tags"><a href="/blog/tags/?tag=Spring%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90" title="标签">#Spring源码分析</a></div> <div class="last-updated"><span class="prefix">最近更新时间：</span> <span class="time">2021/09/15 12:30:11</span></div></div> <div class="page-nav-wapper"><div class="page-nav-centre-wrap"><a href="/blog/pages/47051574c0b3b/" class="page-nav-centre page-nav-centre-prev"><div class="tooltip">Spring基础</div></a> <a href="/blog/pages/eb9794eecd247/" class="page-nav-centre page-nav-centre-next"><div class="tooltip">Spring Cloud基础</div></a></div> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/blog/pages/47051574c0b3b/" class="prev">Spring基础</a></span> <span class="next"><a href="/blog/pages/eb9794eecd247/">Spring Cloud基础</a>→
      </span></p></div></div></div> <div class="theme-vdoing-wrapper article-list bg-style-7"><div class="article-title"><a href="/blog/archives/" class="fa fa-pencil-alt">
      最近更新
    </a></div> <div class="article-wrapper"><dl><dd>01</dd> <dt><div><a href="/blog/pages/6158565fa6669/"><div>数字广东公司工作总结</div></a></div> <div class="date"><span>2021/12/08 09:39:37</span></div></dt></dl><dl><dd>02</dd> <dt><div><a href="/blog/pages/ad577fcaceee3/"><div>Spring Data基础</div></a></div> <div class="date"><span>2021/11/24 16:51:26</span></div></dt></dl><dl><dd>03</dd> <dt><div><a href="/blog/pages/6976a1db349ce/"><div>如何参加github开源项目</div></a></div> <div class="date"><span>2021/11/17 18:29:14</span></div></dt></dl> <div class="more-box"><a href="/blog/archives/" class="more"><i class="fas fa-angle-double-right"></i>前往更多 ...
      </a></div></div></div> <div class="comments-wrapper" style="display:none;"><!----></div></main></div> <div class="footer-wrapper" data-v-4c8cc972 data-v-4c8cc972><span class="footer-reco-theme" data-v-4c8cc972><i class="iconfont reco-github" data-v-4c8cc972></i> <a target="blank" href="https://github.com/YanHui-Yang" data-v-4c8cc972>HuiBlog@1.0</a></span> <!----> <span class="footer-copyright" data-v-4c8cc972><i class="iconfont reco-copyright" data-v-4c8cc972></i> <a data-v-4c8cc972><span data-v-4c8cc972>辉辉</span> <span class="ml5" data-v-4c8cc972>
          2021 - 至今
        </span></a></span> <span class="footer-view-site" data-v-4c8cc972><i class="iconfont reco-eye" data-v-4c8cc972></i> <span id="busuanzi_container_site_uv" data-v-4c8cc972>
        访客数：<span id="busuanzi_value_site_uv" class="num" data-v-4c8cc972>-</span></span> <span id="busuanzi_container_site_pv" class="ml5" data-v-4c8cc972>
        访问量：<span id="busuanzi_value_site_pv" class="num" data-v-4c8cc972>-</span></span></span> <!----></div></div></div><div class="global-ui"><div class="back-to-ceiling" style="right:1rem;bottom:6rem;width:2.5rem;height:2.5rem;border-radius:.25rem;line-height:2.5rem;display:none;" data-v-c6073ba8 data-v-c6073ba8><svg t="1574745035067" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5404" class="icon" data-v-c6073ba8><path d="M526.60727968 10.90185116a27.675 27.675 0 0 0-29.21455937 0c-131.36607665 82.28402758-218.69155461 228.01873535-218.69155402 394.07834331a462.20625001 462.20625001 0 0 0 5.36959153 69.94390903c1.00431239 6.55289093-0.34802892 13.13561351-3.76865779 18.80351572-32.63518765 54.11355614-51.75690182 118.55860487-51.7569018 187.94566865a371.06718723 371.06718723 0 0 0 11.50484808 91.98906777c6.53300375 25.50556257 41.68394495 28.14064038 52.69160883 4.22606766 17.37162448-37.73630017 42.14135425-72.50938081 72.80769204-103.21549295 2.18761121 3.04276886 4.15646224 6.24463696 6.40373557 9.22774369a1871.4375 1871.4375 0 0 0 140.04691725 5.34970492 1866.36093723 1866.36093723 0 0 0 140.04691723-5.34970492c2.24727335-2.98310674 4.21612437-6.18497483 6.3937923-9.2178004 30.66633723 30.70611158 55.4360664 65.4791928 72.80769147 103.21549355 11.00766384 23.91457269 46.15860503 21.27949489 52.69160879-4.22606768a371.15156223 371.15156223 0 0 0 11.514792-91.99901164c0-69.36717486-19.13165746-133.82216804-51.75690182-187.92578088-3.42062944-5.66790279-4.76302748-12.26056868-3.76865837-18.80351632a462.20625001 462.20625001 0 0 0 5.36959269-69.943909c-0.00994388-166.08943902-87.32547796-311.81420293-218.6915546-394.09823051zM605.93803103 357.87693858a93.93749974 93.93749974 0 1 1-187.89594924 6.1e-7 93.93749974 93.93749974 0 0 1 187.89594924-6.1e-7z" p-id="5405" data-v-c6073ba8></path><path d="M429.50777625 765.63860547C429.50777625 803.39355007 466.44236686 1000.39046097 512.00932183 1000.39046097c45.56695499 0 82.4922232-197.00623328 82.5015456-234.7518555 0-37.75494459-36.9345906-68.35043303-82.4922232-68.34111062-45.57627738-0.00932239-82.52019037 30.59548842-82.51086798 68.34111062z" p-id="5406" data-v-c6073ba8></path></svg></div><!----><div></div></div></div>
    <script src="/blog/assets/js/app.4c41a59b.js" defer></script><script src="/blog/assets/js/2.a039f8e7.js" defer></script><script src="/blog/assets/js/29.b316a480.js" defer></script><script src="/blog/assets/js/4.bae9b8d2.js" defer></script>
  </body>
</html>
